// Package structure 结构体辅助操作
package structure

import (
	"fmt"
	"product/common/pointer"
	"reflect"
)

// 默认标签名
var defaultTagName = "json"

// Structure 结构体辅助操作
type Structure struct {
	raw any
	// 类型
	rType reflect.Type
	// 值
	rValue reflect.Value
	// 标签
	TagName string
}

// NewStructure 实例化
// value 支持指针类型
// tagName 支持自定义标签名
// return Structure
func NewStructure(value any, tagName ...string) *Structure {
	value = pointer.ExtractPointer(value)
	v := reflect.ValueOf(value)
	t := reflect.TypeOf(value)
	tagN := defaultTagName
	if len(tagName) > 0 {
		tagN = tagName[0]
	}

	return &Structure{
		raw:     value,
		rType:   t,
		rValue:  v,
		TagName: tagN,
	}

}

// ToMap 结构体转map
// return map[string]any
func (s *Structure) ToMap() (map[string]any, error) {
	if !s.IsStruct() {
		return nil, fmt.Errorf("invalid struct %v", s)
	}
	result := make(map[string]any)
	fields := s.Fields()
	for _, f := range fields {
		if !f.IsExported() || f.tag.IsEmpty() || f.tag.Name == "-" {
			continue
		}

		if f.IsZero() && f.tag.HasOption("omitempty") {
			continue
		}

		if f.IsNil() {
			continue
		}

		result[f.tag.Name] = f.mapValue(f.Value())
	}

	return result, nil
}

// IsStruct 是否是结构体
// return bool
func (s *Structure) IsStruct() bool {
	k := s.rValue.Kind()
	if k == reflect.Invalid {
		return false
	}
	return k == reflect.Struct
}

// Fields 返回所有字段
// return []*Field
// 遍历字段
func (s *Structure) Fields() []*Field {
	var fields []*Field
	for i := 0; i < s.rValue.NumField(); i++ {
		v := s.rValue.Field(i)
		sf := s.rType.Field(i)
		field := newField(v, sf, s.TagName)
		fields = append(fields, field)
	}
	return fields
}

// Field 返回指定字段
// return *Field, bool
func (s *Structure) Field(name string) (*Field, bool) {
	f, ok := s.rType.FieldByName(name)
	if !ok {
		return nil, false
	}
	return newField(s.rValue.FieldByName(name), f, s.TagName), true
}

// ToMap 结构体转map
// return map[string]any
func ToMap(v any) (map[string]any, error) {
	return NewStructure(v).ToMap()
}
